#pragma once

#include <iostream>
#include <vector>
#include <string>
#include <queue>
#include <unistd.h>
#include "thread.hpp"
#include "lockGuard.hpp"
#include "log.hpp"

// 定义默认线程数量常量
const int g_thread_num = 3;

// ThreadPool类模板，基于生产者-消费者模型，用于并发执行不同类型的任务(T)
template <class T>
class ThreadPool
{
public:
    // 返回线程池内部使用的互斥锁
    pthread_mutex_t *getMutex()
    {
        return &lock;
    }

    // 判断任务队列是否为空
    bool isEmpty()
    {
        return task_queue_.empty();
    }

    // 线程等待条件变量，当任务队列为空时阻塞
    void waitCond()
    {
        pthread_cond_wait(&cond, &lock);
    }

    // 从任务队列中取出并移除一个任务
    T getTask()
    {
        T t = task_queue_.front();
        task_queue_.pop();
        return t;
    }

    // ThreadPool构造函数，初始化线程池并创建指定数量的工作线程
    ThreadPool(int thread_num = g_thread_num) : num_(thread_num)
    {
        pthread_mutex_init(&lock, nullptr);
        pthread_cond_init(&cond, nullptr);
        
        // 创建指定数量的工作线程，每个线程运行静态成员函数routine
        for (int i = 1; i <= num_; i++)
        {
            threads_.push_back(new Thread(i, &ThreadPool::routine, this));
        }
    }

    // ThreadPool析构函数，确保所有工作线程正常结束并释放资源
    ~ThreadPool()
    {
        // 等待所有工作线程结束
        for (auto &iter : threads_)
        {
            iter->join();
            delete iter;
        }

        // 销毁互斥锁和条件变量
        pthread_mutex_destroy(&lock);
        pthread_cond_destroy(&cond);
    }

    // 启动所有工作线程
    void run()
    {
        for (auto &iter : threads_)
        {
            iter->start();
            logMessage(NORMAL, "%s %s", iter->name().c_str(), "启动成功");
        }
    }

    // 静态成员函数，作为工作线程的执行入口
    static void *routine(void *args)
    {
        // 解引用指向ThreadPool实例的指针
        ThreadData *td = (ThreadData *)args;
        ThreadPool<T> *tp = (ThreadPool<T> *)td->args_;

        // 循环处理任务
        while (true)
        {
            T task;
            {
                // 使用RAII的lockGuard对任务队列进行加锁
                lockGuard lockguard(tp->getMutex());

                // 等待任务队列非空
                while (tp->isEmpty())
                    tp->waitCond();

                // 从任务队列中取出一个任务
                task = tp->getTask();

            // 退出作用域后，lockGuard自动释放互斥锁，让其他线程有机会添加任务
            }
            task(td->name_);// 执行任务

            // 继续下一轮循环等待新的任务
        }
    }

    // 将新任务推送到线程池的任务队列中
    void pushTask(const T &task)
    {
        // 使用RAII的lockGuard对任务队列进行加锁
        lockGuard lockguard(&lock);

        // 将任务压入任务队列，并发出条件变量信号，通知工作线程有新任务到来
        task_queue_.push(task);
        pthread_cond_signal(&cond);
    }

private:
    // 存储工作线程实例的容器
    std::vector<Thread *> threads_;

    // 工作线程的数量
    int num_;

    // 任务队列，用于存放待执行的任务
    std::queue<T> task_queue_;

    // 用于同步任务队列访问的互斥锁
    pthread_mutex_t lock;

    // 用于通知工作线程有新任务到来的条件变量
    pthread_cond_t cond;
};